#ifdef TSINGMA
#if (FEATURE_MODE == 0)
/**
 @file sys_tsingma_dot1ae.c

 @author  Copyright (C) 2021 Centec Networks Inc.  All rights reserved.

 @date 2021-09-18

 @version v1.0

*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "drv_api.h"
#include "sys_usw_common.h"
#include "sys_usw_dot1ae.h"
#include "sys_tsingma_dot1ae.h"
#include "sys_usw_dma.h"
#include "sys_usw_internal_port.h"
#include "sys_usw_port_api.h"
#include "sys_usw_nexthop_api.h"
/****************************************************************************
 *
* Global and Declaration
*
*****************************************************************************/


/****************************************************************************
 *
* Functions
*
****************************************************************************/

int32
sys_tsingma_dot1ae_add_sc_to_asic(uint8 lchip, void* sys_chan)
{
    uint32 cmd = 0;
    sys_dot1ae_chan_t* p_sys_sec_chan = (sys_dot1ae_chan_t*)sys_chan;
    uint32 sci_hw[2] = {0};
    uint32 key_index = 0;
    uint16 index = 0 ;
    uint32 val_ary[2] ={0};
    DsDot1AeDecryptConfig_m rx_cfg;
    uint8 an = 0;
    uint32 value = 0;
    uint8 step = 0;

    key_index = p_sys_sec_chan->sc_index[0]  <<2;
    /* 1. Set an enable */
    for (an = 0; an < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); an++)
    {
        if (!CTC_IS_BIT_SET(p_sys_sec_chan->an_en, an))
        {
            continue;
        }

        if (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX )
        {
            value = an;
            step = EpeDot1AeAnCtl0_array_1_currentAn_f - EpeDot1AeAnCtl0_array_0_currentAn_f;
            cmd = DRV_IOW(EpeDot1AeAnCtl0_t, EpeDot1AeAnCtl0_array_0_currentAn_f + step * key_index);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
        }
        else
        {
            value = 1;
            key_index = (p_sys_sec_chan->sc_index[0] << 2) + (an & 0x3);
            cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DsDot1AeDecryptConfig_inUse_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index, cmd, &value));
        }
    }
    key_index = p_sys_sec_chan->sc_index[0] <<2;
    if(p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX)
    {
        /* 2. Next an */
        value =  p_sys_sec_chan->next_an;
        step = EpeDot1AeAnCtl1_array_1_nextAn_f - EpeDot1AeAnCtl1_array_0_nextAn_f;
        cmd = DRV_IOW(EpeDot1AeAnCtl1_t, EpeDot1AeAnCtl1_array_0_nextAn_f + step * key_index);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    }
    else
    {
        for(index = 0; index < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); index++)
        {
            /* 3. Replay window size */
            cmd = DRV_IOR(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
            val_ary[0] = p_sys_sec_chan->replayProtectWindow&0xffffffff;
            val_ary[1] = 0;
            SetDsDot1AeDecryptConfig(A, replayWindow_f, &rx_cfg, val_ary);
            cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));

            /* 4. Replay protect enable */
            cmd = DRV_IOR(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
            SetDsDot1AeDecryptConfig(V, replayProtect_f, &rx_cfg, p_sys_sec_chan->replayProtect? 1 : 0);
            cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
        }
    }

    /* 6. SCI */
    if (p_sys_sec_chan->sci)
    {
        SYS_USW_SET_HW_VALUE(sci_hw, p_sys_sec_chan->sci, sizeof(sci_hw));
    }
    cmd = (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_RX) ? DRV_IOW(DsDot1AeSci_t, DsDot1AeSci_sci_f)
    : DRV_IOW(DsEgressDot1AeSci_t, DsEgressDot1AeSci_sci_f);
    for (index = 0; index < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); index++)
    {
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index + index , cmd, &sci_hw));
    }

    return CTC_E_NONE;
}


int32
sys_tsingma_dot1ae_add_sa_to_asic(uint8 lchip, void* sys_chan, uint8 sa_idx, uint32 update_flag)
{
    uint32 cmd = 0;
    uint32 value = 0;
    uint16  key_index   = 0,aes_key_index = 0;
    uint32  cipher_mode = 0;
    uint8  ebit_cbit = 0;
    uint32 ebit_cbit_all[4] = {0};
    uint32 key_len = 0;
    uint32 key_hw[8] = {0};
    uint32  salt_hw[3];
    uint32 pn_mode[4] = {0};
    uint32 next_pn[2] = {0};
    sys_dot1ae_chan_t* p_sys_sec_chan = (sys_dot1ae_chan_t*)sys_chan;

    SYS_DOT1AE_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    key_index = (p_sys_sec_chan->sc_index[0]<< 2) + (p_sys_sec_chan->sa_cfg[sa_idx].an & 0x3);
        /* tx key_index: 0-127; rx key_index: 128-255 */
    aes_key_index = key_index + ((p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX)?0:128);

    SYS_DOT1AE_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "key_index:(%u)  aes_key_index:(%u)    sc_index(%u)    an(%u)\n", key_index,aes_key_index,p_sys_sec_chan->sc_index[0], p_sys_sec_chan->sa_cfg[sa_idx].an);

    /* 1. Next pn */
    if (CTC_FLAG_ISSET(update_flag, CTC_DOT1AE_SA_FLAG_NEXT_PN))
    {
        cmd = (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX) ? DRV_IOW(DsEgressDot1AePn_t, DsEgressDot1AePn_pn_f)
                                    : DRV_IOW(DsDot1AePnCheck_t, DsDot1AePnCheck_nextPn_f);
        next_pn[0] = (p_sys_sec_chan->sa_cfg[sa_idx].next_pn)&0xffffffff;
        next_pn[1] = (p_sys_sec_chan->sa_cfg[sa_idx].next_pn)>>32;
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index, cmd, &next_pn));
    }

    /* 2. Key */
    if (CTC_FLAG_ISSET(update_flag, CTC_DOT1AE_SA_FLAG_KEY))
    {
        key_len = (CTC_DOT1AE_CIPHER_SUITE_GCM_AES_128 == p_sys_sec_chan->sa_cfg[sa_idx].cipher_suite
            || CTC_DOT1AE_CIPHER_SUITE_GCM_AES_XPN_128 == p_sys_sec_chan->sa_cfg[sa_idx].cipher_suite)?(CTC_DOT1AE_KEY_LEN / 2):CTC_DOT1AE_KEY_LEN;
        SYS_USW_SET_HW_VALUE(key_hw, p_sys_sec_chan->sa_cfg[sa_idx].key, key_len);
        cmd = DRV_IOW(DsDot1AeAesKey_t, DsDot1AeAesKey_aesKey_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, aes_key_index, cmd, key_hw));

        sal_memset(salt_hw, 0, sizeof(salt_hw));

        SYS_USW_SET_HW_VALUE(salt_hw,p_sys_sec_chan->sa_cfg[sa_idx].salt, sizeof(salt_hw));
        cmd = DRV_IOW(DsDot1AeAesKey_t, DsDot1AeAesKey_salt_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, aes_key_index, cmd, salt_hw));

        cmd = DRV_IOW(DsDot1AeAesKey_t, DsDot1AeAesKey_ssci_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, aes_key_index, cmd, &p_sys_sec_chan->sa_cfg[sa_idx].ssci));

        value = p_sys_sec_chan->sa_cfg[sa_idx].cipher_suite;
        cmd = DRV_IOW(DsDot1AeAesKey_t, DsDot1AeAesKey_cipherSuite_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, aes_key_index, cmd, &value));

        if(p_sys_sec_chan->sa_cfg[sa_idx].cipher_suite > CTC_DOT1AE_CIPHER_SUITE_GCM_AES_256 && p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX)
        {
            cmd = DRV_IOR(EpePktProcCtl_t, EpePktProcCtl_dot1AePnMode_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, pn_mode));
            CTC_BIT_SET(pn_mode[key_index/32], key_index%32);
            cmd = DRV_IOW(EpePktProcCtl_t, EpePktProcCtl_dot1AePnMode_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, pn_mode));
        }
        else
        {
            cmd = DRV_IOR(EpePktProcCtl_t, EpePktProcCtl_dot1AePnMode_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, pn_mode));
            CTC_BIT_UNSET(pn_mode[key_index/32], key_index%32);
            cmd = DRV_IOW(EpePktProcCtl_t, EpePktProcCtl_dot1AePnMode_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, pn_mode));
        }
    }

    /* 3. cipher mode  */
    if (CTC_FLAG_ISSET(update_flag, CTC_DOT1AE_SA_FLAG_ENCRYPTION))
    {
        cipher_mode = p_sys_sec_chan->sa_cfg[sa_idx].cipher_mode;
        cmd = DRV_IOW(DsDot1AeAesKey_t, DsDot1AeAesKey_cipherMode_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, aes_key_index, cmd, &cipher_mode));

        if (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX)
        {
            cmd = DRV_IOR(EpePktProcCtl_t, EpePktProcCtl_dot1AeTciEbitCbit_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &ebit_cbit_all));
            ebit_cbit = p_sys_sec_chan->sa_cfg[sa_idx].ebit_cbit;
            if(ebit_cbit)
            {
                CTC_BIT_SET(ebit_cbit_all[key_index/32], aes_key_index%32);
            }
            else
            {
                CTC_BIT_UNSET(ebit_cbit_all[key_index/32], aes_key_index%32);
            }
            cmd = DRV_IOW(EpePktProcCtl_t, EpePktProcCtl_dot1AeTciEbitCbit_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &ebit_cbit_all));
        }
    }

    /* 4. check mode */
    if ((CTC_FLAG_ISSET(update_flag, CTC_DOT1AE_SA_FLAG_ICV_ERROR_ACTION)
        || CTC_FLAG_ISSET(update_flag, CTC_DOT1AE_SA_FLAG_VALIDATEFRAMES))
        && p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_RX)
    {
        value = p_sys_sec_chan->sa_cfg[sa_idx].validateFrames;
        cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DsDot1AeDecryptConfig_validateFrames_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index, cmd, &value));
        value = p_sys_sec_chan->sa_cfg[sa_idx].icv_discard;
        cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DsDot1AeDecryptConfig_icvCheckFailDiscard_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index, cmd, &value));
        value = p_sys_sec_chan->sa_cfg[sa_idx].icv_exception;
        cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DsDot1AeDecryptConfig_icvCheckFailException_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index, cmd, &value));
    }

    return CTC_E_NONE;
}


int32
sys_tsingma_dot1ae_register_init(uint8 lchip)
{
    uint32 cmd = 0;
    uint32 value = 0;
    uint32 val_ary[2] = {0};
    uint16 lport = 0;
    EpePktProcCtl_m    epe_pkt_ctl;
    Dot1AeDecryptCtl_m decrypt_ctl;
    IpeIntfMapperCtl_m intf_ctl;

    value = SYS_USW_ILOOP_MIN_FRAMESIZE_DEFAULT_VALUE;
    cmd = DRV_IOW(NetRxMiscChanPktLenChkCtl_t, NetRxMiscChanPktLenChkCtl_cfgMiscMinLen_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 9, cmd, &value));
    cmd = DRV_IOW(NetRxMiscChanPktLenChkCtl_t, NetRxMiscChanPktLenChkCtl_cfgMiscMinLen_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 10, cmd, &value));

    value = MCHIP_CAP(SYS_CAP_PORT_MAX_FRAMESIZE_MAX_VALUE);
    cmd = DRV_IOW(NetRxMiscChanPktLenChkCtl_t, NetRxMiscChanPktLenChkCtl_cfgMiscMaxLen_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 9, cmd, &value));
    cmd = DRV_IOW(NetRxMiscChanPktLenChkCtl_t, NetRxMiscChanPktLenChkCtl_cfgMiscMaxLen_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 10, cmd, &value));

    /* IpeUserIdCtl */
    value = 1;
    cmd = DRV_IOW(IpeUserIdCtl_t, IpeUserIdCtl_unknownDot1AeSciDiscard_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    /*IpeFwdCtl*/
    value = 1;
    cmd = DRV_IOW(IpeFwdCtl_t, IpeFwdCtl_hardErrorDebugEn_f);/*TMM..*/
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    value = 1;
    cmd = DRV_IOW(IpeUserIdCtl_t, IpeUserIdCtl_unknownDot1AePacketDiscard_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    value = 1;
    cmd = DRV_IOW(IpeUserIdCtl_t, IpeUserIdCtl_portLogSelect_f);   /*rx, only mirror plain pkt*/
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    /* EpeHeaderEditCtl */
    value = 0;
    cmd = DRV_IOW(EpeHeaderEditCtl_t, EpeHeaderEditCtl_dot1AeLogMode_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    /*MacSecDecryptCtl*/
    value = 1;
    cmd = DRV_IOW(MacSecDecryptCtl_t, MacSecDecryptCtl_cipherModeMismatchDiscard_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    value = 1;
    cmd = DRV_IOW(MacSecDecryptCtl_t, MacSecDecryptCtl_hostSciLowBits_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    /* IpeIntfMapperCtl */
    cmd = DRV_IOR(IpeIntfMapperCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intf_ctl));

    SetIpeIntfMapperCtl(V, dot1AeDisableLearning_f, &intf_ctl, 1);
    SetIpeIntfMapperCtl(V, bypassPortCrossConnectDisable_f, &intf_ctl, 1);

    cmd = DRV_IOW(IpeIntfMapperCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &intf_ctl));

    /* EpePktProcCtl */
    cmd = DRV_IOR(EpePktProcCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &epe_pkt_ctl));
    val_ary[0] = 0xc0000000;
    SetEpePktProcCtl(A, dot1AePnThreshold_f, &epe_pkt_ctl, val_ary);
    SetEpePktProcCtl(V, dot1AePnMatchSwitchEn_f,    &epe_pkt_ctl, 1);
    SetEpePktProcCtl(V, dot1AePnMatchExceptionEn_f, &epe_pkt_ctl, 0);
    SetEpePktProcCtl(V, dot1AePnOverflowDiscard_f, &epe_pkt_ctl, 1);
    SetEpePktProcCtl(V, dot1AePnOverflowExceptionEn_f, &epe_pkt_ctl, 0);
    SetEpePktProcCtl(V, dot1AeXpnEn_f, &epe_pkt_ctl, 1);

    cmd = DRV_IOW(EpePktProcCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &epe_pkt_ctl));

    /* Dot1AeDecryptCtl */
    cmd = DRV_IOR(Dot1AeDecryptCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &decrypt_ctl));
    val_ary[0] = 0xc0000000;
    val_ary[1] = 0x0;
    SetDot1AeDecryptCtl(A, dot1AePnThreshold_f, &decrypt_ctl, val_ary);

    cmd = DRV_IOW(Dot1AeDecryptCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &decrypt_ctl));

    /* IpeE2iLoopCtl */
    value = 0;
    cmd = DRV_IOW(IpeE2iLoopCtl_t, IpeE2iLoopCtl_dot1AeDecryptPortControlEn_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    value = 1;
    cmd = DRV_IOW(IpeE2iLoopCtl_t, IpeE2iLoopCtl_dot1AeEncryptPortControlEn_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    cmd = DRV_IOW(IpeE2iLoopCtl_t, IpeE2iLoopCtl_dot1AeEncryptedLoopbackPort_f);
    CTC_ERROR_RETURN(sys_usw_internal_port_get_rsv_port(lchip, SYS_INTERNAL_PORT_TYPE_WLAN_ENCAP, 0, &lport));
    value = lport;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    /* QWriteDot1AeCtl */
    value = MCHIP_CAP(SYS_CAP_CHANID_MAC_ENCRYPT);
    cmd = DRV_IOW(QWriteDot1AeCtl_t, QWriteDot1AeCtl_dot1AeEncryptChannel_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
    value = MCHIP_CAP(SYS_CAP_CHANID_MAC_DECRYPT);
    cmd = DRV_IOW(QWriteDot1AeCtl_t, QWriteDot1AeCtl_dot1AeDecryptChannel_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));

    return CTC_E_NONE;
}

STATIC int32
_sys_tsingma_dot1ae_update_sec_chan_an_en(uint8 lchip, void* sys_chan, uint32 an_bitmap)
{
    uint8 an = 0;
    uint32 enable = 0;
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 value = 0;
    uint8 step = 0;
    uint16  key_index   = 0;
    sys_dot1ae_chan_t* p_sys_sec_chan = (sys_dot1ae_chan_t*) sys_chan;

    /*if current sec-chan is binded, add to asic, or update db only*/
    for (an = 0; an < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); an++)
    {
        if (!CTC_IS_BIT_SET(an_bitmap, an)
            && (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX))
        {
            /*rx need clear key when an disable*/
            continue;
        }
        enable = CTC_IS_BIT_SET(an_bitmap, an);

        if (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_TX)
        {
            if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
            {
                value = an;
                step = EpeDot1AeAnCtl0_array_1_currentAn_f - EpeDot1AeAnCtl0_array_0_currentAn_f;
                cmd = DRV_IOW(EpeDot1AeAnCtl0_t, EpeDot1AeAnCtl0_array_0_currentAn_f + step * (p_sys_sec_chan->sc_index[0] << 2));
                ret = DRV_FIELD_IOCTL(lchip, 0, cmd, &value);
            }
           p_sys_sec_chan->an_en = an_bitmap;
        }
        else
        {
            if (enable)
            {
                CTC_BIT_SET(p_sys_sec_chan->an_en, an);
            }
            else
            {
                CTC_BIT_UNSET(p_sys_sec_chan->an_en, an);
            }
            if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
            {
                key_index = (p_sys_sec_chan->sc_index[0] << 2) + (an & 0x3);
                cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DsDot1AeDecryptConfig_inUse_f);
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index, cmd, &enable));
            }
        }
    }

    return ret;
}

int32
sys_tsingma_dot1ae_update_sec_chan(uint8 lchip, void* sys_chan, void* sc)
{
    uint32 cmd =0;
    uint32 value = 0;
    uint32 key_index = 0;
    uint8 step = 0;
    uint32 sci_hw[2] = {0};
    uint32 val_ary[2] ={0};
    uint8 index =0;
    DsDot1AeDecryptConfig_m rx_cfg;
    sys_dot1ae_chan_t* p_sys_sec_chan = (sys_dot1ae_chan_t*)sys_chan;
    ctc_dot1ae_sc_t* p_sc = (ctc_dot1ae_sc_t*)sc;

    if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
    {
        key_index = p_sys_sec_chan->sc_index[0]  <<2;
    }

    /* update sec-chan property in db, if currrent sec-chan is binded, update asic */
    switch (p_sc->property)
    {
    case CTC_DOT1AE_SC_PROP_AN_EN:
        CTC_ERROR_RETURN(_sys_tsingma_dot1ae_update_sec_chan_an_en(lchip,p_sys_sec_chan, p_sc->data));
        break;
    case CTC_DOT1AE_SC_PROP_NEXT_AN:
        p_sys_sec_chan->next_an = p_sc->data;
        if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
        {
            value =  p_sc->data;
            step = EpeDot1AeAnCtl1_array_1_nextAn_f - EpeDot1AeAnCtl1_array_0_nextAn_f;
            cmd = DRV_IOW(EpeDot1AeAnCtl1_t, EpeDot1AeAnCtl1_array_0_nextAn_f + step * key_index);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &value));
        }
        break;
    case CTC_DOT1AE_SC_PROP_INCLUDE_SCI :
        p_sys_sec_chan->include_sci=  p_sc->data ? 1: 0;
        if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
        {
            sys_dot1ae_chan_bind_node_t* p_sec_chan_bind_node = NULL;
            ctc_slistnode_t        *node = NULL;
            if (1 == p_sys_sec_chan->binding_type)
            {
                sys_com_dot1ae_bind_sc_t bind_sc;
                CTC_SLIST_LOOP(p_sys_sec_chan->bind_mem_list, node)
                {
                    p_sec_chan_bind_node = _ctc_container_of(node, sys_dot1ae_chan_bind_node_t, head);
                    sal_memset(&bind_sc, 0, sizeof(bind_sc));
                    bind_sc.include_sci = p_sc->data;
                    bind_sc.gport = p_sec_chan_bind_node->value;
                    CTC_ERROR_RETURN(sys_usw_nh_update_dot1ae(lchip, (void*)(&bind_sc)));
                }
            }
            else if (0 == p_sys_sec_chan->binding_type)
            {
                CTC_SLIST_LOOP(p_sys_sec_chan->bind_mem_list, node)
                {
                    p_sec_chan_bind_node = _ctc_container_of(node, sys_dot1ae_chan_bind_node_t, head);
                    p_sys_sec_chan->gport = p_sec_chan_bind_node->value;
                }
                    value =  p_sc->data;
            }
        }
        break;
    case CTC_DOT1AE_SC_PROP_SCI :
        if (p_sys_sec_chan->sci)
        {
            sal_memcpy(p_sys_sec_chan->sci, (uint8*)p_sc->ext_data, SYS_DOT1AE_SCI_LEN);
        }
        if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
        {
            SYS_USW_SET_HW_VALUE(sci_hw, (uint8*)p_sc->ext_data, sizeof(sci_hw));
            cmd = (p_sys_sec_chan->dir == CTC_DOT1AE_SC_DIR_RX) ? DRV_IOW(DsDot1AeSci_t, DsDot1AeSci_sci_f)
            : DRV_IOW(DsEgressDot1AeSci_t, DsEgressDot1AeSci_sci_f);
            for (index = 0; index < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); index++)
            {
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, key_index + index , cmd, &sci_hw));
            }
        }
        break;
    case CTC_DOT1AE_SC_PROP_REPLAY_WINDOW_SIZE :
        p_sys_sec_chan->replayProtectWindow = p_sc->data;
        if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
        {
            for (index = 0; index < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); index++)
            {
                cmd = DRV_IOR(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
                val_ary[0] = p_sc->data&0xffffffff;
                val_ary[1] = (p_sc->data >> 32)&0xffffffff;
                SetDsDot1AeDecryptConfig(A, replayWindow_f, &rx_cfg, val_ary);
                cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
            }
        }
        break;
    case CTC_DOT1AE_SC_PROP_REPLAY_PROTECT_EN:
        p_sys_sec_chan->replayProtect = p_sc->data;
        if (CTC_SLISTCOUNT(p_sys_sec_chan->bind_mem_list))
        {
            for (index = 0; index < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); index++)
            {
                cmd = DRV_IOR(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
                SetDsDot1AeDecryptConfig(V, replayProtect_f, &rx_cfg, p_sc->data? 1 : 0);
                cmd = DRV_IOW(DsDot1AeDecryptConfig_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index + index, cmd, &rx_cfg));
            }
        }
        break;
    default :
        break;
    }

    return CTC_E_NONE;
}

extern sys_dot1ae_chan_t *
_sys_usw_dot1ae_chan_lookup(uint8 lchip, uint32 chan_id);

int32
sys_tsingma_dot1ae_get_stats(uint8 lchip, uint32 chan_id, void* stats)
{
    uint32  cmd = 0;
    uint8   an = 0;
    uint32 idx = 0;
    uint64 count = 0;
    uint8 an_stats_idx = 0;
    sys_dot1ae_chan_t* p_chan = NULL;
    DsDot1AeDecryptGlobalStats_m rx_glb;
    DsDot1AeDecryptStats_m  rx_stats;
    DsDot1AeEncryptStats_m  tx_stats;
    ctc_dot1ae_stats_t* p_stats = (ctc_dot1ae_stats_t*)stats;
    sys_tm_dot1ae_an_stats_t* p_sys_stats = NULL;

    sal_memset(&rx_glb, 0, sizeof(rx_glb));
    cmd = DRV_IOR(DsDot1AeDecryptGlobalStats_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &rx_glb));

    usw_dot1ae_master[lchip]->global_stats.in_pkts_unknown_sci = GetDsDot1AeDecryptGlobalStats(V, array_0_packetCount_f, &rx_glb);
    usw_dot1ae_master[lchip]->global_stats.in_pkts_no_sci = GetDsDot1AeDecryptGlobalStats(V, array_1_packetCount_f, &rx_glb);

    if (1 == SDK_WORK_PLATFORM)
    {
        sal_memset(&rx_glb, 0, sizeof(rx_glb));
        cmd = DRV_IOW(DsDot1AeDecryptGlobalStats_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &rx_glb));
    }

    p_chan = _sys_usw_dot1ae_chan_lookup(lchip, chan_id);
    if (p_chan == NULL)
    {
        return CTC_E_NOT_EXIST;
    }

    for (an = 0; an < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM); an++)
    {
        if (!CTC_IS_BIT_SET(p_chan->an_valid, an))
        {
            continue;
        }
        if (p_chan->dir == CTC_DOT1AE_SC_DIR_RX )
        {
            for (an_stats_idx = 0; an_stats_idx < 8; an_stats_idx++)
            {
                idx = (((p_chan->sc_index[0] << 2) + (an & 0x3)) << 3) + an_stats_idx;
                sal_memset(&rx_stats, 0, sizeof(rx_stats));
                cmd = DRV_IOR(DsDot1AeDecryptStats_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &rx_stats));
                count = GetDsDot1AeDecryptStats(V, packetCount_f, &rx_stats);

                switch(an_stats_idx)
                {
                case 0:
                    p_stats->an_stats[an].in_pkts_unused_sa = count;
                    break;
                case 1:
                    p_stats->an_stats[an].in_pkts_not_using_sa = count;
                    break;
                case 2:
                    p_stats->an_stats[an].in_pkts_late = count;
                    break;
                case 3:
                    p_stats->an_stats[an].in_pkts_not_valid = count;
                    break;
                case 4:
                    p_stats->an_stats[an].in_pkts_invalid = count;
                    break;
                case 5:
                    p_stats->an_stats[an].in_pkts_delayed = count;
                    break;
                case 6:
                    p_stats->an_stats[an].in_pkts_unchecked = count;
                    break;
                case 7:
                    p_stats->an_stats[an].in_pkts_ok = count;
                    break;
                default:
                    break;

                }

                if (1 == SDK_WORK_PLATFORM)
                {
                    sal_memset(&rx_stats, 0, sizeof(rx_stats));
                    cmd = DRV_IOW(DsDot1AeDecryptStats_t, DRV_ENTRY_FLAG);
                    CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &rx_stats));
                }
            }
        }
        else
        {
            idx = (((p_chan->sc_index[0] << 2) + (an & 0x3)) << 1) + 0;
            cmd = DRV_IOR(DsDot1AeEncryptStats_t, DRV_ENTRY_FLAG);

            sal_memset(&tx_stats, 0, sizeof(tx_stats));
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &tx_stats));
            p_stats->an_stats[an].out_pkts_protected = GetDsDot1AeEncryptStats(V, packetCount_f, &tx_stats);
            idx++;
            sal_memset(&tx_stats, 0, sizeof(tx_stats));
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &tx_stats));
            p_stats->an_stats[an].out_pkts_encrypted = GetDsDot1AeEncryptStats(V, packetCount_f, &tx_stats);

            if (1 == SDK_WORK_PLATFORM)
            {
                sal_memset(&tx_stats, 0, sizeof(tx_stats));
                cmd = DRV_IOW(DsDot1AeEncryptStats_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &tx_stats));
                idx--;
                sal_memset(&tx_stats, 0, sizeof(tx_stats));
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, idx, cmd, &tx_stats));
            }
        }

        /* add stats from db */
        p_sys_stats = (sys_tm_dot1ae_an_stats_t* )(p_chan->an_stats);
        p_stats->an_stats[an].out_pkts_protected += p_sys_stats[an].out_pkts_protected;
        p_stats->an_stats[an].out_pkts_encrypted += p_sys_stats[an].out_pkts_encrypted;
        p_stats->an_stats[an].in_pkts_ok += p_sys_stats[an].in_pkts_ok;
        p_stats->an_stats[an].in_pkts_unchecked += p_sys_stats[an].in_pkts_unchecked;
        p_stats->an_stats[an].in_pkts_delayed += p_sys_stats[an].in_pkts_delayed;
        p_stats->an_stats[an].in_pkts_invalid += p_sys_stats[an].in_pkts_invalid;
        p_stats->an_stats[an].in_pkts_not_valid += p_sys_stats[an].in_pkts_not_valid;
        p_stats->an_stats[an].in_pkts_late += p_sys_stats[an].in_pkts_late;
        p_stats->an_stats[an].in_pkts_not_using_sa += p_sys_stats[an].in_pkts_not_using_sa;
        p_stats->an_stats[an].in_pkts_unused_sa += p_sys_stats[an].in_pkts_unused_sa;

        /* update an_stats in db */
        p_sys_stats[an].out_pkts_protected = p_stats->an_stats[an].out_pkts_protected;
        p_sys_stats[an].out_pkts_encrypted = p_stats->an_stats[an].out_pkts_encrypted;
        p_sys_stats[an].in_pkts_ok = p_stats->an_stats[an].in_pkts_ok;
        p_sys_stats[an].in_pkts_unchecked = p_stats->an_stats[an].in_pkts_unchecked;
        p_sys_stats[an].in_pkts_delayed = p_stats->an_stats[an].in_pkts_delayed;
        p_sys_stats[an].in_pkts_invalid = p_stats->an_stats[an].in_pkts_invalid;
        p_sys_stats[an].in_pkts_not_valid = p_stats->an_stats[an].in_pkts_not_valid;
        p_sys_stats[an].in_pkts_late = p_stats->an_stats[an].in_pkts_late;
        p_sys_stats[an].in_pkts_not_using_sa = p_stats->an_stats[an].in_pkts_not_using_sa;
        p_sys_stats[an].in_pkts_unused_sa = p_stats->an_stats[an].in_pkts_unused_sa;
    }

    p_stats->in_pkts_no_sci += usw_dot1ae_master[lchip]->global_stats.in_pkts_no_sci;
    p_stats->in_pkts_unknown_sci += usw_dot1ae_master[lchip]->global_stats.in_pkts_unknown_sci;

    usw_dot1ae_master[lchip]->global_stats.in_pkts_no_sci = p_stats->in_pkts_no_sci;
    usw_dot1ae_master[lchip]->global_stats.in_pkts_unknown_sci = p_stats->in_pkts_unknown_sci;


    return CTC_E_NONE;
}


STATIC int32
_sys_tsingma_dot1ae_sync_dma_traverse(sys_dot1ae_chan_t* p_sys_chan,void* user_data)
{
    sys_traverse_t* p_user_data = user_data;
    uint8 type = p_user_data->value2;
    uint8 an = 0;
    uint16 aes_key_index = 0;
    uint32* start_addr = (uint32*)p_user_data->data;
    uint16 stats_tx_ptr[2] = {0};
    uint16 stats_rx_ptr[8] = {0};
    sys_tm_dot1ae_an_stats_t* p_sys_stats = (sys_tm_dot1ae_an_stats_t*)(p_sys_chan->an_stats);
    uint8 lchip = p_user_data->value3;

    for (an = 0; an < MCHIP_CAP(SYS_CAP_DOT1AE_AN_NUM);an++)
    {
        aes_key_index = (p_sys_chan->sc_index[0]<< 2) + an + ((p_sys_chan->dir == CTC_DOT1AE_SC_DIR_TX)?0:128);

        stats_tx_ptr[0] = (aes_key_index & 0x7f) << 1;/* out_pkts_protected*/
        stats_tx_ptr[1] = ((aes_key_index & 0x7f) << 1) | 0x1;/* out_pkts_encrypted*/

        stats_rx_ptr[0] = ((aes_key_index & 0x7f) << 3);      /* inPktsUnusedSa*/
        stats_rx_ptr[1] = ((aes_key_index & 0x7f) << 3) | 0x1;/* inPktsNotUsingSa*/
        stats_rx_ptr[2] = ((aes_key_index & 0x7f) << 3) | 0x2;/* inPktsLate*/
        stats_rx_ptr[3] = ((aes_key_index & 0x7f) << 3) | 0x3;/* inPktsNotValid*/
        stats_rx_ptr[4] = ((aes_key_index & 0x7f) << 3) | 0x4;/* inPktsInvalid*/
        stats_rx_ptr[5] = ((aes_key_index & 0x7f) << 3) | 0x5;/* inPktsDelayed*/
        stats_rx_ptr[6] = ((aes_key_index & 0x7f) << 3) | 0x6;/* inPktsUnchecked*/
        stats_rx_ptr[7] = ((aes_key_index & 0x7f) << 3) | 0x7;/* inPktsOk*/

        if(1 == (type%3))/*tx*/
        {
            p_sys_stats[an].out_pkts_protected += start_addr[stats_tx_ptr[0]];
            p_sys_stats[an].out_pkts_encrypted += start_addr[stats_tx_ptr[1]];
        }
        else/*rx*/
        {
            p_sys_stats[an].in_pkts_unused_sa += start_addr[stats_rx_ptr[0]];
            p_sys_stats[an].in_pkts_not_using_sa += start_addr[stats_rx_ptr[1]];
            p_sys_stats[an].in_pkts_late += start_addr[stats_rx_ptr[2]];
            p_sys_stats[an].in_pkts_not_valid += start_addr[stats_rx_ptr[3]];
            p_sys_stats[an].in_pkts_invalid += start_addr[stats_rx_ptr[4]];
            p_sys_stats[an].in_pkts_delayed += start_addr[stats_rx_ptr[5]];
            p_sys_stats[an].in_pkts_unchecked += start_addr[stats_rx_ptr[6]];
            p_sys_stats[an].in_pkts_ok += start_addr[stats_rx_ptr[7]];

        }
    }

    return CTC_E_NONE;
}

int32
sys_tsingma_dot1ae_sync_dma_stats(uint8 lchip, void* p_data)
{
    uint32 type = 0;
    uint32* p_addr = NULL;
    sys_traverse_t user_data;
    sys_dma_reg_t* p_dma_reg = (sys_dma_reg_t*)p_data;
    type = *((uint32*)p_dma_reg->p_ext);
    p_addr = (uint32*)p_dma_reg->p_data;
    sal_memset(&user_data, 0 ,sizeof(sys_traverse_t));
    user_data.value2 = type;
    user_data.data = (void*)p_addr;
    user_data.value3 = lchip;
    CTC_ERROR_RETURN(ctc_hash_traverse(usw_dot1ae_master[lchip]->chan_hash, (hash_traversal_fn)_sys_tsingma_dot1ae_sync_dma_traverse, (void *)&user_data));

    if(0 == (type%3)) /*global*/
    {
        usw_dot1ae_master[lchip]->global_stats.in_pkts_unknown_sci += *(p_addr);
        usw_dot1ae_master[lchip]->global_stats.in_pkts_no_sci += *(p_addr + 1);
    }

    return CTC_E_NONE;
}
#endif
#endif
